﻿using DevExpress.ExpressApp;
using DevExpress.ExpressApp.DC;
using DevExpress.ExpressApp.Editors;
using DevExpress.ExpressApp.Model;
using DevExpress.ExpressApp.Updating;
using DevExpress.ExpressApp.Utils;
using DevExpress.ExpressApp.Xpo;
using EasyXaf.EntityDesigner.BusinessObjects.Entities;
using EasyXaf.EntityDesigner.BusinessObjects.Entities.EntityViews;
using EasyXaf.EntityDesigner.Editors.CodeEditors;
using EasyXaf.EntityDesigner.Editors.DetailViewEditors;
using EasyXaf.EntityDesigner.Editors.EntityAssociationEditors;
using EasyXaf.EntityDesigner.Editors.LookupStringPropertyEditors;
using EasyXaf.EntityDesigner.ModelBuilders;
using EasyXaf.EntityDesigner.Models;
using System.Reflection;

namespace EasyXaf.EntityDesigner;

public sealed class EntityDesignerBlazorModule : ModuleBase
{
    public EntityDesignerBlazorModule()
    {
        DataAccessModeHelper.RegisterEditorSupportedModes(typeof(EntityAssociationEditor), [CollectionSourceDataAccessMode.Client]);
    }

    protected override void RegisterEditorDescriptors(EditorDescriptorsFactory editorDescriptorsFactory)
    {
        base.RegisterEditorDescriptors(editorDescriptorsFactory);

        editorDescriptorsFactory.RegisterListEditorAlias(nameof(EntityAssociationEditor), typeof(Entity), false);
        editorDescriptorsFactory.RegisterListEditor(nameof(EntityAssociationEditor), typeof(Entity), typeof(EntityAssociationEditor), false);

        editorDescriptorsFactory.RegisterPropertyEditorAlias(nameof(DetailViewEditor), typeof(EntityView), false);
        editorDescriptorsFactory.RegisterPropertyEditor(nameof(DetailViewEditor), typeof(EntityView), typeof(DetailViewEditor), false);

        editorDescriptorsFactory.RegisterPropertyEditorAlias(nameof(CodeEditor), typeof(string), false);
        editorDescriptorsFactory.RegisterPropertyEditor(nameof(CodeEditor), typeof(string), typeof(CodeEditor), false);

        editorDescriptorsFactory.RegisterPropertyEditorAlias(nameof(LookupStringPropertyEditor), typeof(string), false);
        editorDescriptorsFactory.RegisterPropertyEditor(nameof(LookupStringPropertyEditor), typeof(string), typeof(LookupStringPropertyEditor), false);
    }

    public override void ExtendModelInterfaces(ModelInterfaceExtenders extenders)
    {
        base.ExtendModelInterfaces(extenders);

        extenders.Add<IModelListView, IModelCurrentDomainModel>();
        extenders.Add<IModelCommonMemberViewItem, IModelCodeEditor>();
    }

    public override IEnumerable<ModuleUpdater> GetModuleUpdaters(IObjectSpace objectSpace, Version versionFromDB)
    {
        return [new DatabaseUpdate.Updater(objectSpace, versionFromDB)];
    }

    public override void CustomizeTypesInfo(ITypesInfo typesInfo)
    {
        base.CustomizeTypesInfo(typesInfo);
        CalculatedPersistentAliasHelper.CustomizeTypesInfo(typesInfo);

        var modelBuilder = new ModelBuilder();

        var entityTypeConfigurationTypes = GetType().Assembly.GetTypes()
            .Where(t => typeof(IEntityTypeConfiguration).IsAssignableFrom(t))
            .Where(t => t.IsClass && !t.IsAbstract)
            .ToArray();

        foreach (var entityTypeConfigurationType in entityTypeConfigurationTypes)
        {
            var entityTypeConfiguration = (IEntityTypeConfiguration)Activator.CreateInstance(entityTypeConfigurationType);
            var entityType = entityTypeConfiguration.EntityType;
            var entityTypeInfo = typesInfo.FindTypeInfo(entityType);
            var entityTypeBuilder = modelBuilder.Entity(entityType, entityTypeInfo);
            var configureMethod = entityTypeConfigurationType.GetMethod("Configure", BindingFlags.Public | BindingFlags.Instance, [typeof(IEntityTypeBuilder)]);
            configureMethod.Invoke(entityTypeConfiguration, [entityTypeBuilder]);
            typesInfo.RefreshInfo(entityTypeInfo);
        }
    }

    public override void Setup(XafApplication application)
    {
        base.Setup(application);
        application.ObjectSpaceCreated += Application_ObjectSpaceCreated;
    }

    private void Application_ObjectSpaceCreated(object sender, ObjectSpaceCreatedEventArgs e)
    {
        if (e.ObjectSpace is CompositeObjectSpace compositeObjectSpace)
        {
            if (compositeObjectSpace.Owner is not CompositeObjectSpace)
            {
                compositeObjectSpace.PopulateAdditionalObjectSpaces((XafApplication)sender);
            }
        }
    }
}
